package io.github.wslxm.springbootplus2.manage.login.util;

import cloud.tianai.captcha.application.ImageCaptchaApplication;
import cloud.tianai.captcha.spring.plugins.secondary.SecondaryVerificationApplication;
import io.github.wslxm.springbootplus2.constant.CacheKey;
import io.github.wslxm.springbootplus2.core.utils.XjIpUtil;
import io.github.wslxm.springbootplus2.core.utils.date.XjLocalDateTimeUtil;
import io.github.wslxm.springbootplus2.manage.sys.model.entity.SysUser;
import io.github.wslxm.springbootplus2.starter.redis.util.RedisUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;

@Component
public class XjLoginUtil {

    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private HttpServletRequest request;
    @Autowired
    private ImageCaptchaApplication imageCaptchaApplication;

    /**
     * 默认环境过期时间
     */
    private static final long DEFAULT_EXP_TIME = 60 * 60 * 24 * 15;
    /**
     * 密码错误次数, 超过则被锁定 (锁定时间，当天23.59.59 结束)
     */
    private static final int PWD_FAIL_LOCKE_NUM = 5;

    /**
     * 设置当前的登录环境
     *
     * @return expTime 保存的环境有效期 (秒)
     */
    public boolean setLoginEnvironment(SysUser user, Long expTime) {
        expTime = expTime == null ? DEFAULT_EXP_TIME : expTime;
        String loginEnvironment = this.getLoginEnvironment();
        String successKey = this.getLoginSuccessKey(user.getUsername());
        return redisUtil.set(successKey, loginEnvironment, expTime);
    }


    /**
     * 进行行为验
     *
     * @return true 行为验通过  false 行为验证不通过
     * @author 王松
     * @mail 1720696548@qq.com
     * @date 2025/6/11 10:28
     */
    public boolean isCaptchaVerify(SysUser user, String captchaId) {
        boolean loginEnvironmentVerify = this.isLoginEnvironment(user);
        if (loginEnvironmentVerify) {
            return true;
        }
        if (StringUtils.isBlank(captchaId)) {
            return false;
        }
        // 环境不同, 验证行为验
        return ((SecondaryVerificationApplication) imageCaptchaApplication).secondaryVerification(captchaId);
    }


    /**
     * 密码连续错误次数记录 (当天内, 如果有登录成功记录就清除)
     *
     * @param user
     * @return
     */
    public void pwdFailRecord(SysUser user) {
        String failKey = this.getLoginFailKey(user.getUsername());
        redisUtil.increment(failKey, 1);
        // 过期时间设置为今天的 23.59.59
        LocalDateTime endTime = XjLocalDateTimeUtil.getDayEnd(LocalDateTime.now());
        long secondsNumber = XjLocalDateTimeUtil.between(LocalDateTime.now(), endTime, ChronoUnit.SECONDS);
        redisUtil.expire(failKey, secondsNumber);
        // 密码错误时删除上次登录成功的记录
        String successKey = this.getLoginSuccessKey(user.getUsername());
        redisUtil.delete(successKey);
    }

    /**
     * 获取剩余的可输入密码次数
     *
     * @param user
     * @return 返回剩余可输入密码次数
     */
    public long getPwaInCount(SysUser user, Integer failLockCount) {
        failLockCount = failLockCount == null ? PWD_FAIL_LOCKE_NUM : failLockCount;
        String failKey = this.getLoginFailKey(user.getUsername());
        if (!redisUtil.hasKey(failKey)) {
            return failLockCount;
        }
        Integer failCount = (Integer) redisUtil.get(failKey);
        return failLockCount - failCount;
    }

    /**
     * 清理登录失败记录
     *
     * @param user
     * @return
     */
    public void cleanPwdFailRecord(SysUser user) {
        String failKey = this.getLoginFailKey(user.getUsername());
        redisUtil.delete(failKey);
    }


    /**
     * 判断当前登录环境和上一次登录的环境是否相同
     *
     * @return true 相同 / false 不相同
     */
    public boolean isLoginEnvironment(SysUser user) {
        String loginEnvironment = this.getLoginEnvironment();
        String preLoginEnvironment = this.getPreLoginEnvironment(user);
        return loginEnvironment.equals(preLoginEnvironment);
    }


    /**
     * 获取上一次登录的登录环境 (最后 setLoginEnvironment 的环境)
     *
     * @return
     */
    private String getPreLoginEnvironment(SysUser user) {
        String successKey = this.getLoginSuccessKey(user.getUsername());
        if (!redisUtil.hasKey(successKey)) {
            return null;
        }
        return redisUtil.get(successKey).toString();
    }

    /**
     * 获取当前登录的登录环境
     *
     * @return
     */
    private String getLoginEnvironment() {
        String currentIp = XjIpUtil.getIp(request);
        String currentUserAgent = request.getHeader("User-Agent");
        return currentIp + '_' + currentUserAgent;
    }


    private String getLoginSuccessKey(String username) {
        return redisUtil.getPrefix(false) + CacheKey.LOGIN_SUCCESS_LOG + username;
    }

    private String getLoginFailKey(String username) {
        return redisUtil.getPrefix(false) + CacheKey.LOGIN_FAIL_LOG + username;
    }
}
